# 目标：计算阶乘
#
# 这个程序展示怎么调用一个递归函数

.section .date

.section .text

msg:
    .string "output: %lld\n"

.globl main
# .globl  factorial # 除非要在其他程序中分享这个函数，
                    # 否则不需要这个。

main:
    push    $6              # 阶乘的参数
    call    factorial       # 运行阶乘函数
    add     $8, %rsp        # 弹出入栈的参数
    mov     %rax, %rbx      # 将返回的参数从rax复制到rbx

    # printf("output: %lld\n", %rsi)
    mov     $0, %rax        # rax必须置零才能call printf成功
    mov     $msg, %rdi      # msg为printf的第一个参数
    mov     %rbx, %rsi      # 运算结果为printf的第二个参数
    call    printf          

    # exit(0)
    mov     $0, %rdi
    call    exit

.type factorial,@function
factorial:
    push    %rbp            # 标准操作--我们必须在返回前恢复rbx
                            # 到之前的状态，因此必须将其入栈

    mov     %rsp, %rbp      # 使用rbp来代替栈指针移动
    
    mov     16(%rbp), %rax  # 将第一个参数移到rax
                            # 8(%rbp)保存的是返回地址
                            # 16(%rbp)保存的是第一个参数
    cmp     $1, %rax        # 等于1时，递归结束
    je      end_factorial

    dec     %rax            # 否则递减值
    push    %rax            # 将参数入栈
    call    factorial

    mov     16(%rbp), %rbx  # 将参数复制到rbx
    imul    %rbx, %rax      # 和factorial的返回值相乘

end_factorial:
    mov     %rbp, %rsp      # 标准处理 -- 将rbp和rsp恢复到函数开始运行前的状态
    pop     %rbp
    ret

# to run this file, follow the commands below
# $ gcc -no-pie recursive.s
# $ ./a.out
# output: 720
